﻿using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using QiAdmin.Core.Models;
using QiAdmin.Core.Services.Cache;
using QiAdmin.Core.Utils;

namespace QiAdmin.Core.Services.Token
{
    public class JwtTokenService : ITokenService
    {
        readonly ICacheService _cacheService;
        public JwtTokenService(ICacheService cacheService)
        {
            _cacheService = cacheService;
        }

        static readonly string tokenTag = App.AppSettings.System.TokenTag;
        static readonly JwtToken jwtToken = App.AppSettings.JwtToken;
        static string checkKey = App.StaticData.CacheKey_CheckToken;
        private string GetToken(HttpContext httpContext)
        {
            if (httpContext == null) throw new SystemException("参数错误");
            return httpContext.Request.Headers[tokenTag];
        }

        public bool CheckToken(HttpContext httpContext)
        {
            string token = GetToken(httpContext);
            if (string.IsNullOrWhiteSpace(token))
            {
                return false;
            }

            TokenData tokenData = ParseToken(httpContext);
            if (_cacheService.Exists(checkKey + tokenData.UserId))
            {
                return false;
            }
            JwtSecurityToken securityToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
            if (securityToken != null)
            {
                TokenValidationParameters Parameters = new()
                {
                    //token是否包含有效期 
                    RequireExpirationTime = true,
                    //是否对Key进行验证
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtToken.Secret)),

                    //验证秘钥的接受人
                    ValidateAudience = true,
                    ValidAudience = jwtToken.Audience,

                    //验证秘钥的发行人
                    ValidateIssuer = true,
                    ValidIssuer = jwtToken.Issuer,

                    //验证令牌是否过期
                    ValidateLifetime = true,

                    //时间验证允许的偏差
                    ClockSkew = TimeSpan.Zero
                };

                new JwtSecurityTokenHandler().ValidateToken(token, Parameters, out SecurityToken _);
                return true;
            }

            return false;
        }
        public string GenerateToken(HttpContext httpContext, TokenData tokenData)
        {
            List<Claim> claims = new();
            var propertys = tokenData.GetType().GetProperties();
            foreach (var property in propertys)
            {
                string? value = Convert.ToString(property.GetValue(tokenData));
                claims.Add(new Claim(property.Name, value));
            }

            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtToken.Secret));
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            var expires = DateTime.Now.AddMinutes(jwtToken.Expiration);
            var securityToken = new JwtSecurityToken(jwtToken.Issuer, jwtToken.Audience, claims, DateTime.Now, expires, signingCredentials);

            string token = new JwtSecurityTokenHandler().WriteToken(securityToken);
            return token;
        }
        public void RemoveToken(HttpContext httpContext)
        {

        }
        public TokenData ParseToken(HttpContext httpContext)
        {
            string token = GetToken(httpContext);
            JwtSecurityToken securityToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
            List<Claim> claims = securityToken.Payload.Claims.ToList();

            TokenData tokenData = new();
            var propertys = tokenData.GetType().GetProperties();
            foreach (var property in propertys)
            {
                property.SetValue(tokenData, ConvertUtil.ConvertValue(claims.Find(s => s.Type == property.Name).Value, property.PropertyType));

            }
            //TokenData tokenData = new TokenData
            //{
            //    UserId = int.Parse(claims.Find(s => s.Type == "UserId").Value),
            //    UserAccount = claims.Find(s => s.Type == "UserAccount").Value,
            //    UserDept = int.Parse(claims.Find(s => s.Type == "UserDept").Value),
            //    UserRole = int.Parse(claims.Find(s => s.Type == "UserRole").Value),
            //    DateTime = Convert.ToDateTime(claims.Find(s => s.Type == "DateTime").Value),
            //};
            return tokenData;
        }

        public string RefreshToken(HttpContext httpContext)
        {
            TokenData tokenData = ParseToken(httpContext);
            string token = GenerateToken(httpContext, tokenData);
            return token;
        }
        public void AddCheckToken(int userId)
        {
            _cacheService.Add(checkKey + userId, 0, new TimeSpan(0, jwtToken.Expiration * 2, 0));
        }
        public void RemoveCheckToken(int userId)
        {
            _cacheService.Remove(checkKey + userId);
        }
    }
}
